﻿using CommunityToolkit.HighPerformance;
using DeHeng_Mes.Constant;
using DeHeng_Mes.Dao;
using DeHeng_Mes.Dao.PlcDao;
using DeHeng_Mes.Model;
using DeHeng_Mes.Model.Boss;
using DeHeng_Mes.Model.BossModel;
using DeHeng_Mes.Model.ConfigModel;
using DeHeng_Mes.Model.OrderSingleton;
using DeHeng_Mes.Model.PlcModel;
using DeHeng_Mes.Model.Singleton;
using DeHeng_Mes.Model.Table;
using DeHeng_Mes.Thread;
using DeHeng_Mes.Utils;
using FluentFTP;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using S7.Net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Shapes;
using Path = System.IO.Path;

namespace DeHeng_Mes.Service
{
    public class PlcService
    {
        #region 成员实例
        PlcDao plcDao = new PlcDao();
        OrderDao orderDao = new OrderDao();
        ViewDao viewDao = new ViewDao();
        ProductionPowerDao productionPowerDao = new ProductionPowerDao();
        List<PlcOrderConfigModel> readPlcList = PlcOrderConfigModelList.ReadPlcList;
        #endregion

        /// <summary>
        /// 获取当日能耗和产量
        /// </summary>
        /// <param name="isTimer"></param>
        public void GetPowerAndProdution(bool isTimer)
        {
            // 检查连接状态并查询工单
            foreach (var item in PlcConnectionManager.plcContainer)
            {
                // 未连接跳出本层
                if (!item.isConnected)
                    continue;

                // 获取Plc数据
                Dictionary<object, Type> dictionary = MappingTable.PlcMapping(item.plc, item.name);

                // 获取当前日期
                DateTime currentDate = DateTime.Now;

                // 获取天
                DateTime previousDate = isTimer ? currentDate.AddDays(-1) : currentDate;

                string day = previousDate.Day.ToString();

                // 获取当前年月日
                string date = $"{previousDate.Year}{previousDate.Month:D2}{previousDate.Day:D2}";

                // 判断当前plcName，执行不同方法
                switch (item.name)
                {
                    case "DOOR-01":
                        break;
                    case "DOOR-02":
                        // 执行当日产量采集
                        Dictionary<string, object> productionDic = plcDao.GetFieldValues(dictionary, "Production");

                        // 初始化产量
                        string production = string.Empty;

                        // 获取产量
                        foreach (var productions in productionDic)
                        {
                            if (productions.Key.Replace("Day", "").Equals(day))
                            {
                                production = productions.Value.ToString();
                            }
                        }

                        // 存入当天产量数据
                        if (!string.IsNullOrEmpty(production))
                        {
                            // 判断产量数据是否保存
                            if (productionPowerDao.ProductionIsSave(item.name, date, production))
                                // 执行更新操作
                                productionPowerDao.UpdateProduction(item.name, date, production);
                            else
                                //执行插入操作
                                productionPowerDao.ProductionSave(item.name, date, production);
                        }
                        break;
                }

                // 执行当日能耗采集
                Dictionary<string, object> powerDic = plcDao.GetFieldValues(dictionary, "Power");

                // 初始化当天能耗
                string power = string.Empty;

                // 获取当天能耗
                foreach (var powers in powerDic)
                {
                    if (powers.Key.Replace("Day", "").Equals(day))
                    {
                        power = powers.Value.ToString();
                    }
                }

                // 存入当天能耗数据
                if (!string.IsNullOrEmpty(power))
                {
                    // 判断能耗数据是否保存
                    if (productionPowerDao.PowerIsSave(item.name, date, power))
                        // 执行更新操作
                        productionPowerDao.UpdatePower(item.name, date, power);
                    else
                        //执行插入操作
                        productionPowerDao.PowerSave(item.name, date, power);
                }
            }
        }

        /// <summary>
        /// 0点监控
        /// </summary>
        public async Task Timer()
        {
            while (true)
            {
                // 获取当前时间
                DateTime now = DateTime.Now;

                // 判断是否为凌晨0点
                // 判断是否为凌晨0点
                if (now.Hour == 0 && now.Minute == 0 && now.Second == 0)
                {
                    GetPowerAndProdution(true);
                }
                await Task.Delay(900);
            }
        }

        /// <summary>
        /// 存储拉铆数据
        /// </summary>
        /// <returns></returns>
        public async Task ReadRiveteData()
        {
            try
            {
                Tools.ProduceLogText("拉铆数据轮询线程启动成功!");

                OrderDao orderDao = new OrderDao();

                while (true)
                {
                    ReveteConnection(orderDao);

                    // 延迟5秒读取
                    await Task.Delay(5000);
                }
            }
            catch (Exception ex)
            {
                Tools.ProduceLogText($"读取并保存拉铆数据发生异常：原因是：{ex.Message}");
            }
        }

        private async void ReveteConnection(OrderDao orderDao)
        {
            try
            {
                DateTime now = DateTime.Now;

                int year = now.Year;

                string month = now.Month.ToString().Length > 1 ? now.Month.ToString() : "0" + now.Month.ToString();

                string day = now.Day.ToString().Length > 1 ? now.Day.ToString() : "0" + now.Day.ToString();

                // 初始化文件夹路径
                string directory = $@"\\192.168.6.209\data\Data_Info\{year}{month}\{year}{month}{day}";

                if (Directory.Exists(directory))
                {

                    try
                    {
                        // 获取目录下所有CSV文件路径
                        string[] csvFiles = Directory.GetFiles(directory, "*.csv");

                        foreach (string filePath in csvFiles)
                        {
                            if (filePath.Contains("_Save"))
                                continue;

                            // 提取文件名和扩展名
                            string fileName = Path.GetFileNameWithoutExtension(filePath);
                            string extension = Path.GetExtension(filePath); // 如 ".csv"

                            // 构建新文件名：原文件名 + "_Save" + 扩展名
                            string newFileName = $"{fileName}_Save{extension}";
                            string newFilePath = Path.Combine(Path.GetDirectoryName(filePath), newFileName);

                            // 调用方法读取文件数据
                            Dictionary<string, string[]> csvData = CsvReaderHelper.ReadCsv(filePath, "钉子二维码");

                            List<TraceRivete> traceRivetes = new List<TraceRivete>();

                            string station = string.Empty;

                            string code = string.Empty;

                            // 循环存储
                            for (int i = 0; i <= csvData["二维码"].Length - 1; i++)
                            {
                                // 实例化存储类
                                TraceRivete traceRivete = new TraceRivete();

                                traceRivete.Result = csvData["结果"][i];

                                traceRivete.DataTime = $"{csvData["日期"][i]}";

                                traceRivete.Pulling = csvData["拉力"][i];

                                traceRivete.PullingMax = csvData["拉力上限"][i];

                                traceRivete.PullingMin = csvData["拉力下限"][i];

                                traceRivete.Displacement = csvData["位移"][i];

                                traceRivete.DisplacementMax = csvData["位移上限"][i];

                                traceRivete.DisplacementMin = csvData["位移下限"][i];

                                code = traceRivete.TraceId = csvData["二维码"][i].Equals("null") ? csvData["批次"][i] : csvData["二维码"][i];

                                traceRivete.PointNo = csvData["点位编号"][i];

                                traceRivete.PointCount = csvData["点位计数"][i];

                                traceRivete.ToolNo = csvData["枪号"][i];

                                station = traceRivete.Station = csvData["工位"][i];

                                // 调用存储
                                if (!orderDao.RiveteDataIsSave(traceRivete.TraceId, traceRivete.PointNo, traceRivete.Station))
                                    orderDao.SaveRiveteData(traceRivete);

                                traceRivetes.Add(traceRivete);

                                Tools.ProduceLogText($"成功保存一条拉铆数据，关联码为{traceRivete.TraceId}");
                            }

                            try
                            {
                                // 重命名文件（如果已存在则跳过或覆盖）
                                if (!File.Exists(newFilePath))
                                {
                                    File.Move(filePath, newFilePath);

                                    //推送拉铆工艺数据
                                    _ = Task.Run(() => { ViewService.InsertLineMesData(code, station, traceRivetes); });

                                    Console.WriteLine($"已打入存储标签: {Path.GetFileName(filePath)} -> {newFileName}");
                                }
                                else
                                {
                                    Console.WriteLine($"文件已存在，跳过: {newFileName}");
                                }
                            }
                            catch (IOException ex)
                            {
                                Console.WriteLine($"标签打入失败: {ex.Message}");
                            }

                            await Task.Delay(100);
                        }
                    }
                    catch (DirectoryNotFoundException)
                    {
                        Tools.ProduceLogTextError($"拉铆数据文件目录不存在: {directory}");
                    }
                    catch (UnauthorizedAccessException)
                    {
                        Tools.ProduceLogTextError("拉铆数据文件没有访问权限，请检查凭据。");
                    }
                    catch (Exception ex)
                    {
                        Tools.ProduceLogTextError($"拉铆数据文件读取发生错误: {ex.Message}");
                    }
                }
                else
                {
                    // 文件夹不存在
                    Tools.ProduceLogText($"拉铆数据文件夹未生成");
                }
                /*using (new NetworkConnection(Path.GetDirectoryName($@"\\192.168.6.209\data\"), new NetworkCredential("Administrator", "asd")))
                {
                    
                }*/
            }
            catch 
            {

            }
        }

        /// <summary>
        /// 产量监控
        /// </summary>
        /// <returns></returns>
        public async Task PartResult()
        {
            Tools.ProduceLogText("产量监控线程启动成功！");

            while (true)
            {
                try
                {
                    List<OrderSingletonModel> orderSingletonModels = OrderSingleton.Instance.Where(x => x.PlcName.Equals("P3") || x.PlcName.Equals("P4")).ToList();

                    if (orderSingletonModels?.Count > 0)
                    {
                        int all = 0;

                        int producessNum = 0;

                        string materialId = string.Empty;

                        string orderId = string.Empty;

                        foreach (var item in orderSingletonModels)
                        {
                            all = all + item.ProducessNumNow;

                            materialId = item.MaterialId;

                            orderId = item.OrderId;

                            producessNum = item.ProducessNum;
                        }

                        if (producessNum <= all)
                        {
                            FactoryMes factoryMes = new FactoryMes();

                            factoryMes.OrderEndOrPause(materialId, "2", orderId);

                            Tools.ProduceLogText($"{orderId}达到设定数量，暂停生产");
                        }
                    }
                }
                catch (Exception e)
                {
                    Tools.ProduceLogTextError(e.Message);
                }
                

                await Task.Delay(2000);
            }
        }

        /// <summary>
        /// 工单下发至Plc
        /// </summary>
        /// <returns></returns>
        public async Task OrderToPlc()
        {
            Tools.ProduceLogText("工单下发线程启动成功！");

            List<string> strings = new List<string>();

            while (true)
            {
                await Task.Delay(1000);

                //BatchCode();

                List<string> orderIds = new List<string>();

                List<OrderSingletonModel> orderModels = OrderSingleton.Instance;

                List<PlcConfigModel> plcContainer = PlcConnectionManager.plcContainer;

                if (!(orderModels?.Count > 0) && plcContainer?.Count > 0)
                    continue;

                foreach (var orderModel in orderModels)
                {
                    S7.Net.Plc plc = plcContainer.Where(x => x.isConnected && x.name.Equals(orderModel.PlcName)).Select(x => x.plc).FirstOrDefault();

                    if (plc == null) continue;

                    // 获取该物料对应工单索引的数据
                    int index = MappingTable.GetOrderIndex(orderModel.MaterialId);

                    string orderId = orderModel.OrderId;

                    int num = orderModel.ProducessNum;

                    string materialCode = orderModel.MaterialId;

                    string status = orderModel.Status;

                    if (orderModel.Status.Equals("9"))
                    {
                        orderIds.Add(orderModel.OrderId);

                        orderId = "";

                        num = 0;

                        materialCode = "";

                        status = "0";
                    }

                    // 写入数据
                    plc.WriteBytes(DataType.DataBlock, SystemConstant.ORDER_DB, index == 1 ? SystemConstant.ORDER_ID_OFF : SystemConstant.ORDER_ID_OFF + ((index - 1) * 516), Tools.ConvertToPlcString(orderId, orderId.Length));
                    plc.Write(DataType.DataBlock, SystemConstant.ORDER_DB, index == 1 ? SystemConstant.ORDER_PRODUCENUM_OFF : SystemConstant.ORDER_PRODUCENUM_OFF + ((index - 1) * 516), short.Parse(Convert.ToInt16(num).ToString()));
                    plc.WriteBytes(DataType.DataBlock, SystemConstant.ORDER_DB, index == 1 ? SystemConstant.ORDER_MATERIALCODE_OFF : SystemConstant.ORDER_MATERIALCODE_OFF + ((index - 1) * 516), Tools.ConvertToPlcString(materialCode, materialCode.Length));
                    plc.Write(DataType.DataBlock, SystemConstant.ORDER_DB, index == 1 ? SystemConstant.ORDER_STATUS_OFF : SystemConstant.ORDER_STATUS_OFF + ((index - 1) * 516), byte.Parse(status));

                    if (!strings.Contains(orderModel.OrderId))
                    {
                        string message = $"工单下发至{orderModel.PlcName}成功，工单号为{orderModel.OrderId}，数量为{orderModel.ProducessNum}，物料编号为{orderModel.MaterialId}";

                        Tools.ProduceLogText(message);

                        strings.Add(orderModel.OrderId);
                    }
                }

                orderIds.ForEach(x => OrderSingleton.RemoveByOrderId(x));
            }
        }

        /// <summary>
        /// 下发批次码方法
        /// </summary>
        private void BatchCode()
        {
            try
            {
                PlcOrderConfigModel plcOrderConfigModel = PlcOrderConfigModelList.ReadPlcList.Where(x => x.PlcName.Equals("Rivet")).FirstOrDefault();

                if (plcOrderConfigModel == null)
                    return;

                if (plcOrderConfigModel.plc.IsConnected)
                {
                    string batchCode = "";

                    //plcOrderConfigModel.plc.WriteBytes(DataType.DataBlock, db, startByteAdr, batchCode);
                }
            }
            catch (Exception ex)
            {
                Tools.ProduceLogTextError($"下发批次码失败，原因是{ex.Message}");
            }
        }
    }
}
